package cn.hicard.risk.action.bd;

import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import cn.hicard.risk.common.Constant;
import cn.hicard.core.Where;
import cn.hicard.risk.entity.BdBusiness;
import cn.hicard.risk.entity.BdCallorder;
import cn.hicard.risk.entity.BdMerchinfo;
import cn.hicard.risk.entity.BdPeriodfreeze;
import cn.hicard.risk.entity.BdTradefileinfo;
import cn.hicard.risk.service.bd.BusinessService;
import cn.hicard.risk.service.bd.CallorderService;
import cn.hicard.risk.service.bd.MerchInfoService;
import cn.hicard.risk.service.bd.PeriodFreezeService;
import cn.hicard.risk.service.bd.TradefileinfoService;
import cn.hicard.util.AppConfig;
import cn.hicard.util.DateHelp;
import cn.hicard.util.WmgwSms;

/**
 * 调单数据生成类
 * @author zhangy
 *
 */
public class CallorderGenerateFlex {
	
	private static Logger logger = Logger.getLogger(Constant.LOGGER_MAIN);
	
	// 调单数据业务类
	private CallorderService callorderservice;
	// 传统POS交易数据业务类
	private TradefileinfoService tradefileinfoService;
	
	// 周期冻结业务类
	private PeriodFreezeService periodFreezeService;
	
	private BusinessService  businessService;
	
	private MerchInfoService merchInfoService;

	
	
	// 是否正在执行调用
	private static boolean runningFlag = false;

	public void setCallorderservice(CallorderService callorderservice) {
		this.callorderservice = callorderservice;
	}

	public void setTradefileinfoService(TradefileinfoService tradefileinfoService) {
		this.tradefileinfoService = tradefileinfoService;
	}

	public void setPeriodFreezeService(PeriodFreezeService periodFreezeService) {
		this.periodFreezeService = periodFreezeService;
	}
	public void setMerchInfoService(MerchInfoService merchInfoService) {
		this.merchInfoService = merchInfoService;
	}
	

	public void setBusinessService(BusinessService businessService) {
		this.businessService = businessService;
	}

	/** 是否正在执行生成 */
	public boolean isExecute(){
		return runningFlag;
	}

	// 多线程同步锁
	private static final Object lock = new Object();
	/**
	 * 生成指定交易日期transdate(yyyyMMdd)调单数据<br/>
	 * 注意本操作在数据量大时比较费时和消耗CPU。<br/>
	 * 本方法是线程同步的，本方法每次只能由一个线程去调用，
	 * 其它线程必须等待上一个线程执行结束，作为防止生成重复数据的首要关卡。
	 * @param transdate交易日期
	 * @return 成功生成的数量，如果发生错误则返回-1
	 */
	public int generate(String transdate){
		runningFlag = true;
		int result = 0;
		synchronized(lock){
			result = execute(transdate);
		}
		runningFlag = false;
		return result;
	}
	
	/**
	 * 执行生成
	 * @param transdate日期
	 * @return 成功处理的数量
	 */
	private int execute(String transdate) {
		// 筛选出的交易日期中需要调单的数据   最终
		List<BdTradefileinfo> trades = new ArrayList<BdTradefileinfo>();
		List<Integer> tradesId = new ArrayList<Integer>();
		//未筛选清算周期
		List<BdTradefileinfo> tradeAll = null;
		//宁波中行落地清算数据
		List<BdTradefileinfo> tradeNing = new ArrayList<BdTradefileinfo>();
		//宁波中行T+2进行周期冻结的
		List<BdTradefileinfo> tradeFreeze = new ArrayList<BdTradefileinfo>();
			
			
		//清算周期为T+2的商户
		List<String> merchPeriodList;
		BdBusiness merchPeriod = new BdBusiness();
		merchPeriod.setReckCycle("T+2");	
		try {
			//查询清算周期为T+2的商户号列表  汇卡商户号
			merchPeriodList = businessService.findPeriodList(merchPeriod);
		
		} catch (Exception e) {
			logger.error("查询清算周期为T+2的商户数据时出错", e);
			return -1;
		}
		
		
		try {
			//根据原调单规则筛选，不考虑周期
			tradeAll = tradefileinfoService.findCallorder(transdate);		
			//调单冻结
			for (int i=0; i<tradeAll.size(); i++){
			    //商圈类的
				if("1".equals(tradeAll.get(i).getCallflag())){
					trades.add(tradeAll.get(i));
					tradesId.add(tradeAll.get(i).getPkTradefileinfo());
				}//宁波中行 T+2 商户才进行调单
				else if(merchPeriodList.contains(tradeAll.get(i).getWpmerchno())){
					BdTradefileinfo ninginfo = tradeAll.get(i);
					ninginfo.setPeriod("T+2");
					trades.add(ninginfo);
					tradesId.add(ninginfo.getPkTradefileinfo());
				}				
			}
		} catch (Exception e) {
			logger.error("查询需要调单的传统POS数据时出错", e);
			return -1;
		}
		
		Where where  = new Where(BdTradefileinfo.class);
		where.addEqual("callflag", "2");
		where.addEqual("transdate", transdate);
		
		try {
			//本交易日期内所有的宁波中行数据
			tradeNing = tradefileinfoService.findByWhere(where);			
		} catch (Exception e) {
			logger.error("查询宁波中行落地清算数据时出错", e);
			return -1;
		}
			
		try {
			//宁波中行T+2商户不符合调单规则的数据，进行周期冻结
			for(int i=0; i<tradeNing.size(); i++){
				if(merchPeriodList.contains(tradeNing.get(i).getWpmerchno())){
					tradeNing.get(i).setPeriod("T+2");
					if(!tradesId.contains(tradeNing.get(i).getPkTradefileinfo())){
						BdTradefileinfo bankinfo = tradeNing.get(i);
						tradeFreeze.add(bankinfo);	
						
						// 判断对应的交易数据是否已经生成了周期冻结数据，以免重复处理
						if(periodFreezeService.existPos(bankinfo.getPkTradefileinfo())){
							logger.warn("主键为" + bankinfo.getPkTradefileinfo() + "的传统POS交易已经生成周期冻结数据，不再做重复处理");
						}else{
						//保存周期冻结数据 
						  saveFreezeInfo(bankinfo);
						}
					}					
				}
				
			}
			logger.info("今日冻结宁波中行T+2商户"+tradeFreeze.size()+"笔交易");
		} catch (Exception e) {
			logger.error("冻结宁波中行T+2商户交易数据时出错", e);
			return -1;
		}
		
		// 统计生成的数量
		int count = 0;	
		// 逐条生成并组装调单数据
				
		if(trades.size() == 0){
			logger.info("交易日期为" + transdate + "的传统POS数据中没有符合紧急调单条件的数据，不执行传统POS调单处理");
			return 0;
		}
		
		
		//需要紧急调单，开始逐条处理......	并排除掉无需调单的商户交易数据	
		logger.info("查询到交易日期为" + transdate + "的传统POS数据中有" + trades.size() + "条符合调单规则");
		logger.info("开始逐条处理，并排除掉无需调单的商户交易数据......");
		for (int i=0; i<trades.size(); i++) {	
			BdTradefileinfo trade = trades.get(i);
			try {
				// 判断对应的交易数据是否已经生成了调单数据，以免重复处理
				if(callorderservice.existPos(trade.getPkTradefileinfo())){
					logger.warn("主键为" + trade.getPkTradefileinfo() + "的传统POS交易已经生成紧急调单数据，不再做重复处理");
				}else{
                    //在商户表查询此订单商户信息
					BdMerchinfo merch = new BdMerchinfo();
					merch.setHmId(trade.getWpmerchno());
					try {
						merch = merchInfoService.getOne(merch);
					} catch (Exception e) {
						logger.error("在商户表查询汇卡商户号为"+trade.getWpmerchno()+"的信息时出错", e);
					}
					//(1)生成金掌柜调单数据 
				    BdCallorder callorder = createAndSave(trade,merch);
					
					if(merch!=null){
					    
					    //(2)发送短信通知用户
					    // 只有包含在“需要调单(发送短信)”的商户号中才发送短信  汇卡商户号
					    if(merch.getGetTicket()!=null && "1".equals(merch.getGetTicket())){						
							sendMessage(callorder,merch);							
						}else{
													
						logger.debug("主键为" + trade.getPkTradefileinfo() + "的传统POS交易数据，由于商户设置为无需调单，因此不发送短信");
							}
					}else{
						logger.warn("交易数据中主键为" + trade.getPkTradefileinfo() + "的数据对应的商户数据不存在！");
					}
					
					
					// 计数
					count++;
				}			
			} catch (Exception e) {
				logger.error("第" + (i+1) + "条主键为" + trade.getPkTradefileinfo() + "的传统POS交易数处理发生错误", e);
			}
		}
		logger.info("交易日期为" + transdate + "的传统POS数据已经全部成功生成紧急调单数据");
		return count;				
	}
	
	/**
	 * 发送对应调单数据的短信
	 * @param callorder
	 */
	private void sendMessage(BdCallorder callorder,BdMerchinfo merch) {
		// 排除一些会影响代码安全性的可能性，虽然正常调用这些可能性按理说不会发生
		if(callorder == null){
			logger.error("调单数据为空,不发送短信");
			return;
		}		

		if(merch.getCellphone() == null || merch.getCellphone().trim().length() == 0){
			logger.error("商户手机号为空,不发送短信");
			return;
		}
		
		String date = callorder.getTransdate();
		String month = date.substring(4,6);
		String day = date.substring(6);
		String money = callorder.getTransmoney();
		String termno = callorder.getTermno();
		String sysno = callorder.getSysno();
		String message = AppConfig.get("callorder_message");
		message = message.replace("{0}", month);
		message = message.replace("{1}", day);
		message = message.replace("{2}", money);
		message = message.replace("{3}", termno);
		message = message.replace("{4}", sysno);
		logger.info("即将给汇卡商户"+merch.getHmId()+"发送到手机号为" + merch.getCellphone() + "的短信内容为：" + message);
		// 发送短信
		String result = WmgwSms.sendMsg(message, merch.getCellphone().trim());
		logger.info("短信发送WebService返回：" + result);
	}
	
	

	// 缓存的商户数据，用于填充调单数据中的商户数据，在日后的更新设中将丢用这一冗余的做法，使用关联
	//private Map<String, LimitMerch> merchs = new HashMap<String, LimitMerch>();
	/**
	 * 创建并保调单数据
	 * @param  trade
	 * @return 创建成功保存OK的调单数据
	 * @throws Exception 
	 */
	private BdCallorder createAndSave(BdTradefileinfo trade,BdMerchinfo merch) throws Exception {

		
		// 如果商户数据未录入的话，调单数据先生成着吧，毕竟还是要处理的。具体的看业务的人员怎么去处理了。
		if(merch == null){
			logger.warn("交易数据中主键为" + trade.getPkTradefileinfo() + "的数据对应的商户数据不存在！生成的调单数据信息部分会缺失！");
			merch = new BdMerchinfo();
		}
				
		BdCallorder callorder = new BdCallorder();
		callorder.setPkTradefileinfo(trade.getPkTradefileinfo());
		callorder.setDatatype("pos");
		callorder.setOrderno(""); // 传统POS交易数据拿不到订单号
		callorder.setBankno(""); // 也没有银行号
		callorder.setTransdate(trade.getTransdate());
		callorder.setTranstime(trade.getTranstime());
		callorder.setCardno(trade.getCardno());
		callorder.setTransmoney(trade.getTransmoney());
		callorder.setTermno(trade.getTermno());
		callorder.setSysno(trade.getSysno());
		
		//callorder.setIsreck(merch.getIsreck()); // 清算类型
		
		callorder.setMerchname(trade.getMerchname());		
		callorder.setMerchno(trade.getMerchno());//银联商户号	
		callorder.setWpmerchno(trade.getWpmerchno());//汇卡商户号
		callorder.setCheckstate("0"); // 状态未处理
		callorder.setPicname("");
		callorder.setCreatedate(DateHelp.dateTime());
		callorder.setCallflag(trade.getCallflag());//调单业务类型
		callorder.setPeriod(trade.getPeriod());//清算周期
		try {
			callorderservice.save(callorder);	
			logger.debug("创建并保存调单数据成功");
		} catch (Exception e) {
			callorder = null;
			logger.error("创建并保存调单数据时出错:", e);			
		}
		return callorder;
	}
  
	/**
	 * 保存清算周期冻结信息
	 * @param trade
	 * @throws Exception
	 */
    private void saveFreezeInfo(BdTradefileinfo trade) throws Exception {
		
		BdPeriodfreeze periodFreeze = new BdPeriodfreeze();
		periodFreeze.setPkTradefileinfo(trade.getPkTradefileinfo());
		periodFreeze.setDatatype("pos");
		periodFreeze.setOrderno(""); // 传统POS交易数据拿不到订单号
		periodFreeze.setBankno(""); // 也没有银行号
		periodFreeze.setTransdate(trade.getTransdate());
		periodFreeze.setTranstime(trade.getTranstime());
		periodFreeze.setCardno(trade.getCardno());
		periodFreeze.setTransmoney(trade.getTransmoney());
		periodFreeze.setTermno(trade.getTermno());
		periodFreeze.setSysno(trade.getSysno());
		periodFreeze.setMerchname(trade.getMerchname());
		periodFreeze.setMerchno(trade.getMerchno());//银联商户号
		periodFreeze.setWpmerchno(trade.getWpmerchno());//汇卡商户号
		periodFreeze.setCreatedate(DateHelp.dateTime());//数据生成日期
		periodFreeze.setCallflag(trade.getCallflag());//调单业务类型
		periodFreeze.setPeriod(trade.getPeriod());//清算周期
		periodFreeze.setIsfreeze("0");//冻结
		try {
			periodFreezeService.save(periodFreeze);	
			logger.debug("清算周期冻结，保存主键为" + trade.getPkTradefileinfo() + "的传统POS交易成功");
		} catch (Exception e) {
			periodFreeze = null;
			logger.error("创建并保存清算周期冻结数据时出错:", e);			
		}
	}
	

}
